package com.yunzai.system.user.controller;

import com.yunzai.file.service.IFileUploadService;
import com.yunzai.generic.domain.JSONResult;
import com.yunzai.generic.service.IEmailService;
import com.yunzai.generic.service.IRedisService;
import com.yunzai.login.domain.Login;
import com.yunzai.secure.domain.LoginUser;
import com.yunzai.secure.exception.ServiceException;
import com.yunzai.secure.service.ITokenService;
import com.yunzai.secure.util.SecurityUtil;
import com.yunzai.system.user.domain.SysUser;
import com.yunzai.system.user.service.ISysUserService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/system/user")
public class SysUserController {

    // 验证码字符集（排除易混淆字符）
    private static final String CHAR_SET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
    private static final int CODE_LENGTH = 4; // 验证码长度
    private static final String CODE_KEY_PREFIX = "yunzai_api_updatePwd_code:";

    private static final int RETRY_NUMBER= 5; // 验证码重试次数
    private static final String CODE_RETRY_NUMBER_KEY_PREFIX = "yunzai_api_updatePwd_code_retry_number:";

    private static final String USER_LOCK_KEY_PREFIX = "yunzai_api_updatePwd_user_lock:";

    @Autowired
    private IRedisService redisService;

    @Autowired
    private IEmailService emailService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private IFileUploadService uploadService;

    @Autowired
    private ITokenService tokenService;

    @PreAuthorize("hasRole('admin')")
    @GetMapping("/list")
    public JSONResult list(SysUser sysUser) {
        List<SysUser> sysUsers = sysUserService.selectSysUserList(sysUser);
        return JSONResult.success(sysUsers);
    }

    @PreAuthorize("hasRole('admin')")
    @GetMapping("/{id}")
    public JSONResult get(@PathVariable("id") Long id) {
        SysUser sysUser = sysUserService.selectSysUserById(id);
        return JSONResult.success(sysUser);
    }

    @GetMapping("/profile")
    public JSONResult profile() {
        LoginUser loginUser = SecurityUtil.getLoginUser();
        SysUser sysUser = sysUserService.selectSysUserById(loginUser.getId());
        return JSONResult.success(sysUser);
    }

    @PutMapping("/profile")
    public JSONResult updateProfile(@RequestBody SysUser sysUser) {
        LoginUser loginUser = SecurityUtil.getLoginUser();
        sysUser.setId(loginUser.getId());
        sysUser.setUsername(null);
        sysUser.setPassword(null);
        sysUser.setEmail(null);
        return JSONResult.toJSONResult(sysUserService.updateSysUser(sysUser));
    }

    @Transactional
    @PostMapping("/profile/avatar")
    public JSONResult avatar(@RequestParam("avatarfile") MultipartFile file, HttpServletRequest request) {
        LoginUser loginUser = SecurityUtil.getLoginUser();
        SysUser sysUser = new SysUser();
        sysUser.setId(loginUser.getId());
        String filename = uploadService.uploadAvatar(file);
        String avatar = "/avatar/" + filename;
        sysUser.setAvatar(avatar);

        loginUser.setAvatar(avatar);
        tokenService.update(request, loginUser);

        return JSONResult.toJSONResult(sysUserService.updateSysUser(sysUser));
    }

    @GetMapping("/profile/updatePwd/code")
    public JSONResult code() {
        String email = SecurityUtil.getLoginUser().getEmail();
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < CODE_LENGTH; i++) {
            int index = random.nextInt(CHAR_SET.length());
            code.append(CHAR_SET.charAt(index));
        }
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String key = CODE_KEY_PREFIX + uuid;
        // 存储到Redis，设置过期时间（例如5分钟）
        redisService.setValue(key, code, 5, TimeUnit.MINUTES);
        emailService.sendVerificationEmail(email, code.toString());
        JSONResult data = new JSONResult();
        data.put("uuid", uuid);
        return JSONResult.success(data);
    }

    @PutMapping("/profile/updatePwd")
    public JSONResult updatePwd(@RequestBody Login login) {
        System.out.println(login);
        verifyCode(login.getCode(), login.getUuid(),login.getUsername());
        LoginUser loginUser = SecurityUtil.getLoginUser();
        SysUser sysUser = new SysUser();
        sysUser.setId(loginUser.getId());
        sysUser.setPassword(passwordEncoder.encode(login.getPassword()));
        return JSONResult.toJSONResult(sysUserService.updateSysUser(sysUser));
    }

    private void verifyCode(String code, String uuid, String username) {
        String isLock = redisService.getValue(USER_LOCK_KEY_PREFIX + username);
        if ("true".equals(isLock)) {
            throw new ServiceException("验证码错误次数已达上限！请10分钟后重试！");
        }
        String key = CODE_KEY_PREFIX + uuid;
        String storedCode = redisService.getValue(key);
        Integer retryNumber = redisService.getValue(CODE_RETRY_NUMBER_KEY_PREFIX + username);
        if (storedCode == null) {
            throw new ServiceException("验证码已过期！");
        } else if (!storedCode.equalsIgnoreCase(code)) {
            if (retryNumber != null) {
                if (retryNumber >= RETRY_NUMBER) redisService.setValue(USER_LOCK_KEY_PREFIX + username, "true", 10, TimeUnit.MINUTES);
                redisService.setValue(CODE_RETRY_NUMBER_KEY_PREFIX + username, retryNumber + 1, 1, TimeUnit.MINUTES);
            } else {
                redisService.setValue(CODE_RETRY_NUMBER_KEY_PREFIX + username, 1, 1, TimeUnit.MINUTES);
            }
            redisService.deleteValue(key);
            throw new ServiceException("验证码错误!");
        }
        redisService.deleteValue(key);
    }

}
